using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace ScreenSnapper
{
    class BitmapTcpServer
    {
        public const int PORT = 4887;

        public static void StartServer(ScreenSnapper screenSnapper)
        {
            s_screenSnapper = screenSnapper;
            Thread t = new Thread(new ThreadStart(TcpServerThreadProc));
            t.Start();
        }

        public static void RequestExit()
        {
            if (null != s_server)
            {
                s_server.ExitRequest = true;
            }
        }

        public static void TcpServerThreadProc()
        {
            BitmapTcpServer server = new BitmapTcpServer();
            s_server = server;
            server.Listen();
        }

        private static ScreenSnapper s_screenSnapper;
        private static BitmapTcpServer s_server;

        private bool _exitRequest;
        public bool ExitRequest
        {
            get
            {
                return _exitRequest;
            }
            set
            {
                _exitRequest = value;
            }
        }

        BitmapTcpServer()
        {
            _exitRequest = false;
        }

        public void Listen()
        {
            int port = PORT;
            TcpListener server = null;
            try
            {
                server = new TcpListener(IPAddress.Any, port);
                server.Start();

                while (!ExitRequest)
                {
                    while (!ExitRequest && !server.Pending())
                    {
                        Thread.Sleep(100);
                    }

                    if (!ExitRequest)
                    {
                        TcpClient client = server.AcceptTcpClient();
                        NetworkStream stream = client.GetStream();

                        HandleRequest(stream);

                        client.Close();
                    }
                }
            }
            catch (SocketException /*e*/)
            {
            }
            finally
            {
                server.Stop();
            }
        }

        private void HandleRequest(NetworkStream stream)
        {
            if (SendImageTypeResponse(stream))
            {
                SendFileData(stream);
            }
        }

        private void SendFileData(NetworkStream stream)
        {
            string fileToSend = s_screenSnapper.LastSnappedFile;
            byte[] data = File.ReadAllBytes(fileToSend);
            long length = data.Length;
            stream.Write(LongToByteArray(length), 0, 4);
            stream.Write(data, 0, data.Length);
        }

        private byte[] LongToByteArray(long length)
        {
            byte[] data = new byte[4];
            data[0] = (byte)(length & 0x000000ff);
            data[1] = (byte)((length & 0x0000ff00) >> 8);
            data[2] = (byte)((length & 0x00ff0000) >> 16);
            data[3] = (byte)((length & 0xff000000) >> 24);
            return data;
        }

        private bool SendImageTypeResponse(NetworkStream stream)
        {
            string lastSnappedFile = s_screenSnapper.LastSnappedFile;
            string response = "NO ";
            bool returnValue = true;
            if (null == lastSnappedFile)
            {
                returnValue = false;
            }
            else
            {
                response = "JPG";
                if (lastSnappedFile.IndexOf("PNG", 0, StringComparison.InvariantCultureIgnoreCase) >= 0)
                    response = "PNG";
            }

            stream.Write(StringToByteArray(response), 0, response.Length);

            return returnValue;
        }

        private byte[] StringToByteArray(string response)
        {
            byte[] data = new byte[response.Length];
            for (int i = 0; i < response.Length; ++i)
            {
                data[i] = (byte)response[i];
            }
            return data;
        }
    }
}
